from django.contrib.auth import get_user_model
from .models import ChatRoom,RoomMessage
from celery import shared_task
from django.conf import settings
from channels.layers import get_channel_layer
from asgiref.sync import async_to_sync
import logging
import requests
from django.utils import timezone
from celery.exceptions import MaxRetriesExceededError
logger = logging.getLogger(__name__)
User = get_user_model()
@shared_task(bind=True, max_retries=3, default_retry_delay=30)
# bind表示这个任务是一个“绑定任务”（bound task），任务的第一个参数会是 self（即任务实例本身）。
# 这样你就可以在任务内部访问任务的各种属性和方法，例如 self.retry() 用于重试任务，或者 self.request 获取任务的元数据（如 task_id、args、kwargs 等）。
# max_retries是重试次数，后面的是重试的时间间隔30秒
def save_room_message(self,room_id,user_id,message,timestamp,is_deepseek):
    try:
        room = ChatRoom.objects.get(id=room_id)
        user = User.objects.get(id=user_id)
        RoomMessage.objects.create(
            room=room,
            user=user,
            content=message,
            timestamp=timestamp,
            is_deepseek=is_deepseek
        )
        logger.info(f"房间{room_id}中，来自用户id为{user_id}的信息被保存")
    # except (room.DoesNotExist,user.DoesNotExist)
    # 不能用变量名，如果变量名存在说明已经查询成功，用模型名称
    except (ChatRoom.DoesNotExist, User.DoesNotExist) as exc:
        logger.error(f'保存失败：{exc}')  # 捕捉异常到变量exe
    except Exception as exc:
        logger.error(f'捕捉到了其他异常{exc}')
        try:
            self.retry(exc=exc)
            # exc=exc 将当前捕获的异常对象传递给重试机制，Celery 会记录该异常详情（如堆栈跟踪），便于调试。
            # 设置bing=true后，函数里的self就变成了shared_task
        except MaxRetriesExceededError:
            logger.error(f'重试保存信息太多次超过重试上限了')
            # self.retry没有调用递归，而是结束当前任务并重试
@shared_task(bind=True, max_retries=3, default_retry_delay=60)
def fetch_deepseek_reply(self,group_id,room_id,user_name,message,api):
    if not api:
        logger.warning('api未设置')
        return
    try:
        # user_msg = list(user.user_room_messages.filter(room_id=room_id).order_by('-timestamp')[:10].values_list('content', flat=True))
        headers = {
            'Authorization': f'Bearer {api}',
            'Content-Type': 'application/json'
        }
        payload = {
            'model': 'deepseek-chat',
            'messages':[{
                'role':'user',
                'content':f"用户{user_name}说：{message}。请用中文回复，并尽可能像人类一样。",
            }],
            # 前十条聊天记录为{user_msg},
            'temperature': 0.7,
            'max_tokens':500
        }
        resp = requests.post(
            settings.DEEPSEEK_API_URL,
            headers=headers,
            json=payload,
            timeout=30
        )
        data = resp.json()
        reply = data['choices'][0]['message']['content'].strip()
        room = ChatRoom.objects.get(id=room_id)
        channels_layer = get_channel_layer()
        async_to_sync(channels_layer.group_send)(
            group_id,
            {
                'type':'chat_message',
                'message':reply,
                'sender':'deepseek',
                'timestamp':timezone.now().isoformat(),
                'require_deepseek': False,
                'is_deepseek':True
            }
        )
        RoomMessage.objects.create(
            room=room,
            user=User.objects.get(username='deepseek'),
            content=reply,
            is_deepseek=True
        )
    except requests.RequestException as exc:
        logger.error(f"API有误 {exc}")
        try:
            self.retry(exc=exc)
        except MaxRetriesExceededError:
            logger.error("达到连接deepseek最大重试此事")
    except Exception as exc:
        logger.exception("Unexpected error in fetch_deepseek_reply")